--- A base class for log handler.
-- @author zrong
-- Creation: 2014-11-14

local LogHandler = class('LogHandler')

LogHandler.TABLE_DPSTEP = 5     --default table-log deepstep level

LogHandler.LOGNAME = {
    [10] = "DEBUG",
    [20] = "INFO",
    [30] = "WARNING",
    [40] = "ERROR",
    [50] = "CRITICAL",
}

local function _isfmt(fmt)
    return type(fmt) == 'string' and string.find(fmt, "%%")
end

local function dump_value_(v)
    if type(v) == "string" then
        v = "\"" .. v .. "\""
    end
    return tostring(v)
end


-- @starttime 
-- @gettime A function, return current time.
function LogHandler:ctor(starttime, gettime)
    self._gettime = nil
    self._starttime = nil
    if starttime then
        self._gettime = gettime or os.time
        self._starttime = (starttime == 0 and self._gettime()) or starttime
    end
    self._basefmt = "[dlog]"
end

function LogHandler:emit(level, fmt, args)
end

function LogHandler:dumpemit(level, tb, tbname, nesting)
end

function LogHandler:flush()
end

function LogHandler:getString(level, fmt, args)
    local ret = ""
    if self._starttime then
        ret = string.format('[%.4f]', self._gettime()-self._starttime)..ret
    end
    if (#args > 0) then 
        if _isfmt(fmt) then 
            ret = string.format(fmt, unpack(args))
        else 
            ret = ret..fmt
            for param in ipairs(args) do 
                ret = ret .. tostring(param)
            end
        end
    else 
        ret = ret..tostring(fmt)
    end
    return self:getFmtStr(level, ret)
end

function LogHandler:setFmt(fmtstr)
    self._basefmt = fmtstr
end

function LogHandler:getFmtStr(level, retstr)
    local str_lvname = self.LOGNAME[level]
    local str = "%s-%s-%s: %s\n"
    return string.format(str, self._basefmt, str_lvname, ngx.now(), retstr)
end

-- 字典转换字符串
-- @function getTBString
-- @tparam tb dict  字典内容
-- @tparam tbname string 字典名称
function LogHandler:getTBString(level, tb, tbname, nesting)
    if type(nesting) ~= "number" then nesting = LogHandler.TABLE_DPSTEP end
    local lookupTable = {}
    local result = {}

    local traceback = string.split(debug.traceback("", 2), "\n")

    local function dump_(value, desciption, indent, nest, keylen)
        desciption = desciption or "var"
        local spc = ""
        if type(keylen) == "number" then
            spc = string.rep(" ", keylen - string.len(dump_value_(desciption)))
        end
        if type(value) ~= "table" then
            result[#result +1 ] = string.format("%s%s%s = %s", indent, dump_value_(desciption), spc, dump_value_(value))
        elseif lookupTable[tostring(value)] then
            result[#result +1 ] = string.format("%s%s%s = *REF*", indent, dump_value_(desciption), spc)
        else
            lookupTable[tostring(value)] = true
            if nest > nesting then
                result[#result +1 ] = string.format("%s%s = *MAX NESTING*", indent, dump_value_(desciption))
            else
                result[#result +1 ] = string.format("%s%s = {", indent, dump_value_(desciption))
                local indent2 = indent.."    "
                local keys = {}
                local keylen = 0
                local values = {}
                for k, v in pairs(value) do
                    keys[#keys + 1] = k
                    local vk = dump_value_(k)
                    local vkl = string.len(vk)
                    if vkl > keylen then keylen = vkl end
                    values[k] = v
                end
                table.sort(keys, function(a, b)
                    if type(a) == "number" and type(b) == "number" then
                        return a < b
                    else
                        return tostring(a) < tostring(b)
                    end
                end)
                for i, k in ipairs(keys) do
                    dump_(values[k], k, indent2, nest + 1, keylen)
                end
                result[#result +1] = string.format("%s}", indent)
            end
        end
    end
    dump_(tb, tbname, "- ", 1)
    local retstr = ""
    for i, line in ipairs(result) do
        retstr = retstr..line.."\n"
    end
    return self:getFmtStr(level, retstr)
end
return LogHandler
